package com.icloud.wallet.boot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.icloud.common.cache.constants.CacheConstants;
import com.icloud.common.cache.service.RedisService;
import com.icloud.common.core.api.ResultCode;
import com.icloud.common.database.enums.*;
import com.icloud.common.database.mapper.AppCustomerMapper;
import com.icloud.common.database.mapper.CustomerWalletMapper;
import com.icloud.common.database.mapper.RedPacketMapper;
import com.icloud.common.database.mapper.RedPacketReceiveMapper;
import com.icloud.common.database.model.CustomerWallet;
import com.icloud.common.database.model.RedPacket;
import com.icloud.common.database.model.RedPacketReceive;
import com.icloud.common.web.exception.Asserts;
import com.icloud.common.web.util.AuthUtil;
import com.icloud.wallet.boot.dto.ReceiveRedPacketDto;
import com.icloud.common.database.mapper.TWalletJournalMapper;
import com.icloud.common.database.model.TWalletJournal;
import com.icloud.wallet.boot.service.RedPacketReceiveService;
import com.icloud.wallet.boot.vo.ReceiveRedPacketVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

@Slf4j
@Service
public class RedPacketReceiveServiceImpl extends ServiceImpl<RedPacketReceiveMapper, RedPacketReceive> implements RedPacketReceiveService {
    @Autowired
    private AuthUtil authUtil;
    @Autowired
    private RedisService redisService;
    @Autowired
    private RedPacketMapper redPacketMapper;
    @Autowired
    private AppCustomerMapper appCustomerMapper;
    @Autowired
    private CustomerWalletMapper customerWalletMapper;
    @Autowired
    private TWalletJournalMapper tWalletJournalMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ReceiveRedPacketVo receive(ReceiveRedPacketDto dto) {
        Long redPacketId = dto.getRedPacketId();
        RedPacket redPacket = redPacketMapper.selectById(redPacketId);
        Asserts.fail(null==redPacket, ResultCode.DATA_NOT_EXISTS);

        // 红包有效期
        String key = CacheConstants.CACHE_RED_PACKET + redPacketId;
        Object amountObj = redisService.get(key);
        Asserts.fail(null==amountObj, ResultCode.THE_RED_PACKET_IS_INVALID);

        String handleState = redPacket.getHandleState();
        Asserts.fail(RedPacketHandleStateEnum.isExpire(handleState), ResultCode.THE_RED_PACKET_IS_INVALID);

        // 红包已被领取完毕
        BigDecimal amount = redPacket.getAmount();
        BigDecimal amtReceived = redPacket.getAmtReceived();
        Asserts.fail(amount.compareTo(amtReceived)<=0 || RedPacketHandleStateEnum.isHandled(handleState),
                ResultCode.THE_RED_PACKET_HAS_BEEN_COLLECTED);

        Long receiveId = dto.getReceiveId();
        Long loginId = authUtil.getUserId();
        // 红包领取人和登录人应该是同一人
        Asserts.fail(!loginId.equals(receiveId), ResultCode.VALIDATE_FAILED);

        String rpType = redPacket.getType();
        // 专属红包或普通红包,只能是指定的人才能领取
        if(RedPacketTypeEnum.isExclusive(rpType) || RedPacketTypeEnum.isSingleNormal(rpType)){
            Asserts.fail(!receiveId.equals(redPacket.getReceiveId()), ResultCode.YOU_CANNOT_CLAIM_THE_RED_PACKET);
        }

        LambdaQueryWrapper<CustomerWallet> walletQuery = new LambdaQueryWrapper<>();
        walletQuery.eq(CustomerWallet::getCustomerId, loginId);
        CustomerWallet wallet = customerWalletMapper.selectOne(walletQuery);
        Asserts.fail(null==wallet, ResultCode.DATA_NOT_EXISTS);

        BigDecimal beforeBal = wallet.getBcpc();
        BigDecimal afterBal = beforeBal.add(amount);

        // 生成流水
        TWalletJournal rewardJournal = TWalletJournal.builder()
                .customerId(loginId)
                .journalType(JournalTypeEnum.RECV_RED_PKT.getCode())
                .beforeBalance(beforeBal)
                .amount(amount)
                .afterBalance(afterBal)
                .currency(CurrencyEnum.BCPC.getCode())
                .direction(DirectionEnum.DEBIT.getCode())
                .journalState(JournalStateEnum.FINISHED.getCode())
                .remark("领取红包流水,红包Id:"+redPacketId)
                .createdId(loginId)
                .updatedId(loginId)
                .build();
        tWalletJournalMapper.insert(rewardJournal);

        // 修改钱包余额
        CustomerWallet walletUpdate = CustomerWallet.builder()
                .id(wallet.getId())
                .bcpc(afterBal)
                .build();
        customerWalletMapper.updateById(walletUpdate);

        // 记录接收红包
        RedPacketReceive redPacketReceive = new RedPacketReceive();
        redPacketReceive.setAmtReceived(amount);
        redPacketReceive.setRedPacketId(redPacketId);
        redPacketReceive.setRedPacketCreatedId(redPacket.getCreatedId());
        redPacketReceive.setCreatedId(receiveId);
        baseMapper.insert(redPacketReceive);

        RedPacket redPacketUpdate = new RedPacket();
        redPacketUpdate.setId(redPacketId);
        redPacketUpdate.setAmtReceived(amount);
        redPacketUpdate.setHandleState(RedPacketHandleStateEnum.HANDLED.getCode());
        redPacketMapper.updateById(redPacketUpdate);

        return new ReceiveRedPacketVo(redPacket, amount);
    }
}
